<template>
  <div id="home">
    <!-- 导航 -->
    <nav-bar class="home-nav">
      <div slot="center">购物街</div>
    </nav-bar>

    <!-- 狸猫换太子: 通过v-show显示与隐藏 -->
    <tab-control
      v-show="isTabFixed"
      ref="tabControl1"
      class="home-tab-control"
      :titles="titles"
      @tabClick="controlCLick"
    ></tab-control>

    <!-- 滚动组件 -->
    <scroll
      class="home-content-view"
      ref="scroll"
      @scroll="changeScroll"
      @pullingup="loadMoreData"
      :probe-type="3"
      :pull-up-load="true"
    >
      <!-- 轮播图 -->
      <home-swiper :banners="banners" @swiperImageLoad.once="swiperImageLoad"></home-swiper>

      <!-- 推荐 -->
      <recommend-view :recommends="recommends"></recommend-view>

      <!-- 本周流行 -->
      <feature-view class="home-recommend"></feature-view>

      <!-- 商品控制导航 -->
      <tab-control ref="tabControl2" :titles="titles" @tabClick="controlCLick"></tab-control>

      <!-- 商品展示列表 -->
      <goods-list :goods="showGoods"></goods-list>
    </scroll>

    <!-- 返回顶部小icon 自定义组件监听点击需要加上.native修饰符 -->
    <back-top @click.native="backTop" v-show="isShowBack"></back-top>
  </div>
</template>

<script>
// 引入公共组件
import NavBar from "components/common/navbar/NavBar";
import TabControl from "components/content/tabControl/TabControl";
import GoodsList from "components/content/goods/GoodsList";
import Scroll from "components/common/scroll/Scroll";

// 引入子组件
import HomeSwiper from "./childComps/HomeSwiper";
import RecommendView from "./childComps/RecommendView";
import FeatureView from "./childComps/FeatureView";

// 引入后端API
import { getHomeMultidata, getHomeGoods } from "@/api";

// 引入工具类
import { debounce } from "utils/utils";

// 引入混入对象
import { backTopMixin } from "utils/mixin";

export default {
  name: "Home",

  // 组件注册
  components: {
    NavBar,
    TabControl,
    GoodsList,
    Scroll,
    HomeSwiper,
    RecommendView,
    FeatureView,
  },

  // 组件数据
  data() {
    return {
      titles: ["流行", "新款", "精选"],
      banners: [],
      recommends: [],
      // 商品数据存储对象
      goods: {
        pop: { page: 0, list: [] },
        new: { page: 0, list: [] },
        sell: { page: 0, list: [] },
      },
      // 当前展示类型
      currentType: "pop",
      // tab-control组件距离顶部距离
      tabOffsetTop: 0,
      // tab-control是否吸顶
      isTabFixed: false,
      // Home组件不活跃时保存better-scroll移动的y轴
      saveY: 0,
    };
  },

  // 混入对象注册
  mixins: [backTopMixin],

  // 计算属性
  computed: {
    // 当前类别显示商品列表
    showGoods() {
      return this.goods[this.currentType].list;
    },
  },

  // 回调 >>> 组件被创建时
  created() {
    this.getData();
  },

  // 回调 >>> 组件被挂载后
  mounted() {
    // 创建一个防抖函数
    const refresh = debounce(this.$refs.scroll.refresh, 100);

    // 1. 监听GoodsItem中图片加载完成 >>> [事件总线]
    this.$bus.$on("homeItemImgLoad", () => {
      // console.log("加载完成");
      // this.$refs.scroll.refresh();
      // 调用防抖函数
      refresh();
    });

    // 2. 手动触发一次tab-control的点击事件
    this.controlCLick(0);
  },

  // 组件使用了keep-alive后就可以使用 activated + deactivated
  // 组件活跃 >>> 显示
  activated() {
    // console.log("[home] 组件活跃了", this.saveY);
    this.$refs.scroll.scrollTo(0, this.saveY, 100);
  },

  // 组件不活跃 >>> 隐藏
  deactivated() {
    // console.log("[home] 组件不活跃了", this.saveY);
    // 1. 保存Y值
    this.saveY = this.$refs.scroll.getScrollY();

    // 2. 取消全局事件监听
    // this.$bus.$off("事件名", 取消函数);
  },

  // 回调 >>> 组件被销毁
  destroyed() {
    console.log("[home] 该组件被销毁");
  },

  // 组件方法
  methods: {
    // =============================================== 后端API ===============================================
    // 题外话: 函数调用的过程？
    // 函数调用时 >>> 压入函数栈 [保存函数调用过程中所有的变量]
    // 函数调用结束后 >>> 弹出函数函数栈 [释放掉函数所有变量]
    getData() {
      // 请求轮播图、推荐列表等多个数据
      getHomeMultidata().then((res) => {
        console.log("[正常] 多个类型数据 >>>", res);
        const data = res.data;
        this.banners = data.banner.list;
        this.recommends = data.recommend.list;
      });

      // 请求各个类别数据 使用Object.keys() 获取对象中的类别属性并逐个调用请求方法
      Object.keys(this.goods).forEach((item) => {
        // console.log("[请求] 类别 >>>", item);
        this._getGoodsData(item);
      });
      // this.getGoodsData("pop");
      // this.getGoodsData("new");
      // this.getGoodsData("sell");
    },

    // 请求首页商品数据
    // isFinsh: 是否需要调用better-scroll中的上拉加载完成事件, 默认不调用
    // _私有函数
    _getGoodsData(type, isFinsh = false) {
      // 页面请求应该是该类型已经记录到多个页+1的数据, 所以如下
      let currentGoods = this.goods[type];
      // 对当前类别的页码加1
      let page = ++currentGoods.page;
      getHomeGoods({ type, page }).then((res) => {
        console.log("[正常] 首页商品数据 >>>", res);
        // 返回结果为数组, 使用...扩展运算符解构后push值原数组
        currentGoods.list.push(...res.data.list);

        // 上拉加载任务完成 可以进行下次上拉加载更多了 >>> 告诉better-scroll我完成了
        isFinsh && this.$refs.scroll.finishPullUp();
      });
    },

    //=============================================== 事件监听 ===============================================
    // 商品控制导航点击
    controlCLick(index) {
      // console.log("[tab-control] 下标 >>>", index);
      // 1. 通过switch切换
      // switch (index) {
      //   case 0:
      //     this.currentType = "pop";
      //     break;
      //   case 1:
      //     this.currentType = "new";
      //     break;
      //   case 2:
      //     this.currentType = "sell";
      //     // 最后的braak写不写都行, 但是如果还有下一个case就一定要写, 因为可能会造成case穿透
      //     break;
      // }
      // 2. 按照顺序将商品中所有属性去除, 点击时取出对应属性给到当前类别 [简洁]
      this.currentType = Object.keys(this.goods)[index];
      // 3. 两个tab-control选项保持同步
      this.$refs.tabControl1.currentIndex = index;
      this.$refs.tabControl2.currentIndex = index;
    },

    // 滚动区域发生改变
    changeScroll(position) {
      // 1. [BackTop是否显示] 因为我们向下滚动是y轴往下走 所以y轴为负数, 我们直接 [负负得正] 就完了
      // this.isShowBack = -position.y > BACK_POSITION; ps: 混入对象中查找 用于监听是否显示BackTop的
      this.listenShowBack(position.y);

      // 2. [tabControl是否有吸顶效果]
      this.isTabFixed = -position.y > this.tabOffsetTop;
    },

    // 上拉加载更多数据
    loadMoreData() {
      console.log(`[上拉加载任务] >>> ${this.currentType}`);
      this._getGoodsData(this.currentType, true);
    },

    // 轮播图加载完成事件
    swiperImageLoad() {
      // 1. 获取tab-control组件距离顶部的值
      // 所有的组件都有一个 $el 用于获取组件中的元素
      this.tabOffsetTop = this.$refs.tabControl2.$el.offsetTop;
      // console.log("[tab-control] 距离顶部像素 >>>", this.tabOffsetTop);
    },
  },
};
</script>

<style lang="less" scoped>
#home {
  // height: 2000px;
  // 设置顶部内边距调整轮播图等区域位置
  // padding-top: 44px;
  position: relative;
  height: 100vh;
  .home-nav {
    // 首页导航
    // 设置固定定位, 固定导航条 ps: 使用better-scroll后无需
    // position: fixed;
    // left: 0;
    // right: 0;
    // top: 0;
    // z-index: 999;
    color: var(--color-background);
    background-image: linear-gradient(
      to right,
      var(--color-tint),
      var(--color-high-text)
    );
  }
  .home-content-view {
    // 首页滚动区域内容
    // margin-top: 44px;
    // height: calc(100% - 93px);
    position: absolute;
    top: 44px;
    bottom: 49px;
    left: 0;
    right: 0;
    overflow: hidden;
    .fixed {
      // 固定定位在距离顶部44像素的位置
      position: fixed;
      top: 44px;
      left: 0;
      right: 0;
    }
  }
  // 狸猫换太子 >>> 我直呼666
  .home-tab-control {
    position: relative;
    z-index: 999;
  }
}
</style>
